/*
 * Copyright 2010-2012 Susanta Tewari. <freecode4susant@users.sourceforge.net>
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package coalescent.br;

import coalescent.data.PopGenData;
import coalescent.model.PopGenModel;

import commons.core.Statistic;

import java.math.BigDecimal;
import java.util.List;

/**
 * Describes a chain of transitionTypes that creates a sample configuration from the MRCA. An event in
 * the chain is of type {@code BREvent} and it describes the sample configurations and the type of
 * population genetic event that affected it.
 *
 * @param <E>
 * @param <M>
 * @param <D>
 * @param <S>
 * @param <R>
 * @author Susanta Tewari
 * @version 1.0 Nov 17, 2010
 */
public class BRGenealogy<E extends Enum<E>, M extends PopGenModel<E>,
                         D extends PopGenData<?, E, M, D>, S extends Statistic<D, S>,
                         R extends BRSPopGen<?, ?, E, M, D, S, R>> {

    /** Field description */
    private final R recursionConfig;

    /** Field description */
    private List<BREvent<E, M, D, S, R>> recursionChain;

    /**
     * Creates an instance of this object from the specified event chain leading up to the
     * specified sample configuration.
     *
     * @param recursionConfig the sample configuration that the specified {@code eventChain} leads up
     * to
     * @param recursionChain the chain of transitionTypes from the specified sample configuration
     * {@code sampleConfig} to all the way up to the MRCA
     *         prev.getConfig().applyEvent(prev.getType()).contains(next.getConfig())} returns {@code true}
     *         </pre>
     */
    @SuppressWarnings("JavaDoc")
    public BRGenealogy(R recursionConfig, List<BREvent<E, M, D, S, R>> recursionChain) {

        this.recursionConfig = recursionConfig;
        this.recursionChain  = recursionChain;
    }

    /**
     * The probability of this genealogy.
     *
     * @return the probability of this genealogy
     */
    public BigDecimal probability() {

        BigDecimal prob = BigDecimal.valueOf(1.0);
        R r             = recursionConfig;

        for (BREvent<E, M, D, S, R> event : recursionChain) {

            R ancestralConfig = event.getConfig();
            E type            = event.getType();

            prob = prob.multiply(recursionConfig.transitionProb(type, ancestralConfig));
            r    = ancestralConfig;
        }

        return prob;
    }

    /**
     * The chain of transitionTypes from the MRCA corresponding to this genealogy
     *
     * @return the chain of transitionTypes corresponding to this genealogy
     */
    public List<BREvent<E, M, D, S, R>> getEventChain() {
        return recursionChain;
    }

    /**
     * A textual representation of this genealogy. It has information on the sample configurations
     * and their event types starting from the sample configuration all the way up to the
     * MRCA. It does not end with a new line character.
     *
     * @return a textual representation of this genealogy
     */
    @Override
    public String toString() {

        StringBuilder builder = new StringBuilder();
        String delimeter      = "->";

        builder.append(recursionConfig).append(delimeter);

        for (BREvent event : recursionChain) {

            builder.append(event).append(delimeter);
        }

        builder.delete(builder.lastIndexOf(delimeter), builder.length());

        return builder.toString();
    }

    /**
     * A textual representation of this genealogy with information on only the event types by their
     * abbreviations.
     *
     * @return a textual representation of this genealogy using abbreviation of the event types
     */
    public String toStringEventSeq() {

        StringBuilder builder = new StringBuilder();

        for (BREvent event : recursionChain) {

            builder.append(event.getType());
        }

        return builder.toString();
    }
}
